﻿using System;
using System.Reflection.Emit;

namespace Aeon.Emulator.Decoding.Emitters
{
    /// <summary>
    /// Emitter for decoding a segment register.
    /// </summary>
    internal sealed class LoadSegmentRegister : Emitter
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the LoadSegmentRegister class.
        /// </summary>
        /// <param name="state">Common emitter state information.</param>
        public LoadSegmentRegister(EmitStateInfo state)
            : base(state)
        {
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets the type of local variable needed to store the operand value as a method argument.
        /// </summary>
        public override Type MethodArgType
        {
            get
            {
                if(this.ReturnType == EmitReturnType.Value)
                    return typeof(ushort);
                else
                    return typeof(SegmentIndex);
            }
        }
        /// <summary>
        /// Gets a value indicating whether a temporary variable is required.
        /// </summary>
        public override bool? RequiresTemp
        {
            get { return this.ReturnType == EmitReturnType.Address; }
        }
        /// <summary>
        /// Gets the type of temporary variable that is required.
        /// </summary>
        public override Type TempType
        {
            get { return typeof(ushort); }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Emits IL for the operation.
        /// </summary>
        public override void EmitLoad()
        {
            //// Reg is the middle 3 bits of the ModR/M byte.
            //int reg = (*ip & 0x38) >> 3;

            if(this.ReturnType == EmitReturnType.Value)
                LoadProcessor();

            //il.LoadLocal(ipPointer);
            LoadIPPointer();
            il.Emit(OpCodes.Ldind_U1);
            il.LoadConstant(0x38);
            il.Emit(OpCodes.And);
            il.LoadConstant(3);
            il.Emit(OpCodes.Shr_Un);

            if(this.ReturnType == EmitReturnType.Value)
            {
                il.Emit(OpCodes.Call, Infos.Processor.GetSegmentRegisterPointer);
                il.Emit(OpCodes.Ldind_U2);
            }
        }
        #endregion
    }
}
